package com.example.demo.controller;


import com.example.demo.domain.DifyWorkflowRunResult;
import com.example.demo.domain.FileInput;
import com.example.demo.domain.FileUploadResponse;
import com.example.demo.domain.WorkflowRequest;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

@CrossOrigin(origins = "http://localhost:5173")
@RestController
@RequestMapping("/api/dify")
public class DifyController {

    @Value("${dify.api.key}")
    private String difyApiKey;

    @Value("${dify.api.url}")
    private String difyApiUrl;

    // ObjectMapper 实例，推荐作为成员变量，避免重复创建和资源浪费
    private final ObjectMapper objectMapper = new ObjectMapper(); // 移到这里作为成员变量

    // 上传文件到Dify
    @PostMapping("/upload")
    public ResponseEntity<?> uploadFile( // 将返回类型改为<?>以支持返回错误信息
                                         @RequestParam("file") MultipartFile file,
                                         @RequestParam(value = "user", required = false) String user) {

        try {
            // 1. 构建请求URL

            String uploadUrl = difyApiUrl + "/v1/files/upload";

            // 2. 创建HTTP客户端
            CloseableHttpClient httpClient = HttpClients.createDefault();
            HttpPost httpPost = new HttpPost(uploadUrl);

            // 3. 设置请求头
            httpPost.setHeader("Authorization", "Bearer " + difyApiKey);

            // 4. 处理文件名以支持中文和特殊字符
            String originalFilename = file.getOriginalFilename();
            System.out.println("用户上传的原始文件名: " + originalFilename);


            String sanitizedFilename = URLEncoder.encode(originalFilename, StandardCharsets.UTF_8.toString())
                    .replace("+", "%20")
                    .replaceAll("[^a-zA-Z0-9.\\-_%\\u4e00-\\u9fa5]", "_");

            System.out.println("处理后的文件名 (用于Dify): " + sanitizedFilename);

            // 5. 构建多部分请求体
            MultipartEntityBuilder builder = MultipartEntityBuilder.create();
            builder.addBinaryBody("file", file.getInputStream(),
                    ContentType.parse(file.getContentType()),
                    sanitizedFilename); // 使用处理后的文件名

            if (user != null) {
                builder.addTextBody("user", user);
            }

            httpPost.setEntity(builder.build());

            // 6. 发送请求并获取响应
            CloseableHttpResponse response = httpClient.execute(httpPost);
            HttpEntity httpEntity = response.getEntity();
            String responseBody = httpEntity != null ? EntityUtils.toString(httpEntity) : ""; // 避免空指针

            // 调试输出Dify API的原始响应
            System.out.println("--- Dify API 响应原始体 START ---");
            System.out.println("Dify API HTTP 状态码: " + response.getStatusLine().getStatusCode());
            System.out.println("Dify API 响应内容: " + responseBody);
            System.out.println("--- Dify API 响应原始体 END ---");

            // 7. 解析响应
            int statusCode = response.getStatusLine().getStatusCode();

            if (statusCode == HttpStatus.OK.value()||statusCode == HttpStatus.CREATED.value()) { // 检查HTTP状态码是否为200 OK 或 201 Created
                // Dify API成功响应，解析为FileUploadResponse
                // 使用成员变量的 objectMapper
                FileUploadResponse uploadResponse = objectMapper.readValue(responseBody, FileUploadResponse.class);
                return ResponseEntity.ok(uploadResponse);
            } else {
                // Dify API返回错误状态码 (例如400 Bad Request)
                System.err.println("Dify API 返回错误状态码: " + statusCode);
                System.err.println("错误详情: " + responseBody);

                // 返回 JSON 格式的错误给前端
                return ResponseEntity.status(statusCode).body("{\"error\": \"Dify API error\", \"details\": \"" + responseBody.replace("\"", "\\\"") + "\"}");
            }

        } catch (Exception e) {
            e.printStackTrace();
            // 在生产环境中，这里应该返回一个更友好的错误信息，而不是直接暴露栈追踪
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body("{\"error\": \"文件上传失败\", \"details\": \"" + e.getMessage().replace("\"", "\\\"") + "\"}");
        }
    }


    // 执行工作流 (修改为调用 executeWorkflow 方法)
    @PostMapping("/runWorkflow")
    public ResponseEntity<String> runWorkflow(@RequestBody WorkflowRequest workflowRequest) {

        try {
            // 调试输出后端接收到的前端请求体
            String receivedRequestBodyJson = objectMapper.writeValueAsString(workflowRequest);
            System.out.println("--- 后端接收到的前端请求体 START ---");
            System.out.println("接收到的参数对象: " + workflowRequest.toString());
            System.out.println("转换成JSON后的原始请求体: " + receivedRequestBodyJson);
            System.out.println("--- 后端接收到的前端请求体 END ---");

            // 调用通用的 executeWorkflow 方法来执行工作流
            String result = executeWorkflow(workflowRequest);

            return ResponseEntity.ok(result);

        } catch (IOException e) { // 捕获 executeWorkflow 抛出的 IOException
            System.err.println("Dify API 通信错误: " + e.getMessage());
            e.printStackTrace();
            return ResponseEntity.status(HttpStatus.BAD_GATEWAY) // 502 Bad Gateway
                    .body("{\"error\": \"AI批改失败: 与Dify API通信错误\", \"details\": \"" + e.getMessage().replace("\"", "\\\"") + "\"}");
        } catch (Exception e) { // 捕获其他未知异常
            e.printStackTrace();
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body("{\"error\": \"执行工作流失败\", \"details\": \"" + e.getMessage().replace("\"", "\\\"") + "\"}");
        }
    }


    @PostMapping("/runWorkflowWithCosUrl")
    public ResponseEntity<String> runWorkflowWithCosUrl(
            @RequestParam String requestFileUrl,
            @RequestParam String reviewFileUrl,
            @RequestParam(required = false) String user) {

        // 确保传递了用户 ID，Dify 通常需要
        if (user == null || user.trim().isEmpty()) {
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("{\"error\": \"User ID is required for Dify workflow.\"}");
        }

        File requestTempFile = null;
        File reviewTempFile = null;

        try {
            // 1. 从COS下载文件到临时目录
            System.out.println("开始下载请求文件从COS: " + requestFileUrl);
            requestTempFile = downloadFromCos(requestFileUrl);
            System.out.println("请求文件下载完成: " + requestTempFile.getAbsolutePath());

            System.out.println("开始下载审查文件从COS: " + reviewFileUrl);
            reviewTempFile = downloadFromCos(reviewFileUrl);
            System.out.println("审查文件下载完成: " + reviewTempFile.getAbsolutePath());

            // 2. 上传到Dify
            System.out.println("开始上传请求文件到Dify...");
            FileUploadResponse requestUpload = uploadToDify(requestTempFile, user);
            System.out.println("请求文件上传Dify成功，ID: " + requestUpload.getId());

            System.out.println("开始上传审查文件到Dify...");
            FileUploadResponse reviewUpload = uploadToDify(reviewTempFile, user);
            System.out.println("审查文件上传Dify成功，ID: " + reviewUpload.getId());

            // 3. 执行工作流
            System.out.println("开始构建工作流请求并执行...");
            WorkflowRequest workflowRequest = new WorkflowRequest();

            // 构建 inputs Map
            Map<String, FileInput> inputs = new HashMap<>();
            // 'request' 和 'review' 这里的键名需要与你在 Dify 工作流中定义的输入变量名称完全匹配
            inputs.put("request", createFileInput(requestUpload.getId()));
            inputs.put("review", createFileInput(reviewUpload.getId()));
            workflowRequest.setInputs(inputs); // 设置 inputs

            workflowRequest.setResponseMode("blocking"); // 根据实际需求确定是 "streaming" 还是 "blocking"
            workflowRequest.setUser(user);

            String result = executeWorkflow(workflowRequest); // 调用通用的 executeWorkflow 方法
            System.out.println("工作流执行完成，结果: " + result);

            return ResponseEntity.ok(result);

        }  catch (IOException e) { // 专门捕获来自 Dify API 调用的 IOException
            System.err.println("Dify API 通信错误: " + e.getMessage());
            e.printStackTrace();
            return ResponseEntity.status(HttpStatus.BAD_GATEWAY)
                    .body("{\"error\": \"AI批改失败: 与Dify API通信错误\", \"details\": \"" + e.getMessage().replace("\"", "\\\"") + "\"}");
        }
        catch (Exception e) {
            System.err.println("执行工作流过程中发生错误: " + e.getMessage());
            e.printStackTrace();
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body("{\"error\": \"AI批改失败: 内部服务器错误\", \"details\": \"" + e.getMessage().replace("\"", "\\\"") + "\"}");
        } finally {
            // 4. 确保删除临时文件，无论成功或失败
            if (requestTempFile != null && requestTempFile.exists()) {
                if (requestTempFile.delete()) {
                    System.out.println("临时请求文件删除成功: " + requestTempFile.getAbsolutePath());
                } else {
                    System.err.println("临时请求文件删除失败: " + requestTempFile.getAbsolutePath());
                }
            }
            if (reviewTempFile != null && reviewTempFile.exists()) {
                if (reviewTempFile.delete()) {
                    System.out.println("临时审查文件删除成功: " + reviewTempFile.getAbsolutePath());
                } else {
                    System.err.println("临时审查文件删除失败: " + reviewTempFile.getAbsolutePath());
                }
            }
        }
    }

    /**
     * 从 COS URL 下载文件到临时文件
     * @param cosUrl COS 文件的 URL
     * @return 临时文件对象
     * @throws IOException 如果下载失败
     */
    private File downloadFromCos(String cosUrl) throws IOException {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpGet httpGet = new HttpGet(cosUrl);

        try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
            HttpEntity entity = response.getEntity();

            if (response.getStatusLine().getStatusCode() != HttpStatus.OK.value()) {
                String errorBody = EntityUtils.toString(entity);
                throw new IOException("从COS下载文件失败，状态码: " + response.getStatusLine().getStatusCode() + ", 错误: " + errorBody);
            }
            if (entity == null) {
                throw new IOException("从COS下载文件，响应实体为空。");
            }

            File tempFile = File.createTempFile("cos-download-", ".tmp");
            try (FileOutputStream outStream = new FileOutputStream(tempFile)) {
                entity.writeTo(outStream);
            }
            return tempFile;
        } finally {
            httpClient.close(); // 确保关闭 HttpClient
        }
    }

    /**
     * 上传本地文件到 Dify API
     * @param file 要上传的本地文件
     * @param user 用户ID
     * @return Dify 的文件上传响应
     * @throws IOException 如果上传失败或Dify返回非成功状态码
     */
    private FileUploadResponse uploadToDify(File file, String user) throws IOException {
        String uploadUrl = difyApiUrl + "/v1/files/upload";
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost(uploadUrl);

        httpPost.setHeader("Authorization", "Bearer " + difyApiKey);

        // 文件名处理：支持中文和特殊字符
        String originalFilename = file.getName();
        String sanitizedFilename = URLEncoder.encode(originalFilename, StandardCharsets.UTF_8.toString())
                .replace("+", "%20")
                .replaceAll("[^a-zA-Z0-9.\\-_%\\u4e00-\\u9fa5]", "_");
        System.out.println("上传Dify时使用的文件名: " + sanitizedFilename);

        MultipartEntityBuilder builder = MultipartEntityBuilder.create();
        builder.addBinaryBody("file", file,
                ContentType.APPLICATION_OCTET_STREAM, // 可以根据文件类型更精确地设置ContentType
                sanitizedFilename); // 使用处理后的文件名

        if (user != null) {
            builder.addTextBody("user", user);
        }

        httpPost.setEntity(builder.build());

        try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
            HttpEntity httpEntity = response.getEntity();
            String responseBody = httpEntity != null ? EntityUtils.toString(httpEntity) : "";

            int statusCode = response.getStatusLine().getStatusCode();

            // 检查 Dify API 的响应状态码
            if (statusCode == HttpStatus.OK.value() || statusCode == HttpStatus.CREATED.value()) {
                return objectMapper.readValue(responseBody, FileUploadResponse.class);
            } else {
                throw new IOException("上传文件到Dify失败，状态码: " + statusCode + ", 响应: " + responseBody);
            }
        } finally {
            httpClient.close(); // 确保关闭 HttpClient
        }
    }

    /**
     * 构建 Dify 工作流所需的 FileInput 对象
     * @param fileId 已上传到 Dify 的文件ID
     * @return FileInput 对象
     */
    private FileInput createFileInput(String fileId) {
        FileInput fileInput = new FileInput();
        fileInput.setType("document");
        fileInput.setTransferMethod("local_file"); // 注意这里是 camelCase，Jackson 会通过 @JsonProperty 映射到 snake_case
        fileInput.setUploadFileId(fileId); // 注意这里是 camelCase，Jackson 会通过 @JsonProperty 映射到 snake_case
        return fileInput;
    }

    /**
     * 执行 Dify 工作流 (现在所有工作流执行都通过此方法)
     * @param workflowRequest 包含工作流参数的请求对象
     * @return Dify 工作流的原始响应字符串
     * @throws IOException 如果执行失败或Dify返回非成功状态码
     */
    private String executeWorkflow(WorkflowRequest workflowRequest) throws IOException {
        String workflowUrl = difyApiUrl + "/v1/workflows/run";
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost(workflowUrl); // <-- We explicitly create a POST object here

        httpPost.setHeader("Authorization", "Bearer " + difyApiKey);
        httpPost.setHeader("Content-Type", "application/json");

        String requestBodyToDify = objectMapper.writeValueAsString(workflowRequest);
        System.out.println("--- 即将发送给 Dify API 的工作流请求体 START ---");
        System.out.println("请求 URL: " + workflowUrl);
        System.out.println("请求方法: POST"); // <-- Add this line for clarity
        System.out.println("请求体: " + requestBodyToDify);
        System.out.println("--- 即将发送给 Dify API 的工作流请求体 END ---");

        httpPost.setEntity(new StringEntity(requestBodyToDify, ContentType.APPLICATION_JSON));

        try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
            HttpEntity httpEntity = response.getEntity();
            String responseBody = "";
            if (httpEntity != null) {
                responseBody = EntityUtils.toString(httpEntity);
            }

            int statusCode = response.getStatusLine().getStatusCode();

            System.out.println("--- Dify API 工作流响应 START ---");
            System.out.println("Dify API HTTP 状态码: " + statusCode);
            System.out.println("Dify API 响应内容: " + responseBody);
            System.out.println("--- Dify API 工作流响应 END ---");

            // 如果 Dify 返回 200 OK 或 201 Created，则表示成功
            if (statusCode == HttpStatus.OK.value() || statusCode == HttpStatus.CREATED.value()) {

                    // 返回前可以先解析，或者直接返回原始字符串，由上层调用者解析
                    // 为了演示解码，我们可以在这里将其转换为对象
                    DifyWorkflowRunResult resultObject = objectMapper.readValue(responseBody, DifyWorkflowRunResult.class);
                    System.out.println("解码后的Dify输出: " + resultObject.getData().getOutputs().get("output"));
                    return resultObject.getData().getOutputs().get("output"); // 仍然返回原始字符串，前端会处理

            } else {
                // 对于任何其他状态码（包括 504），抛出一个详细的 IOException
                throw new IOException("Dify API 返回错误状态码: " + statusCode + ", 响应: " + responseBody);
            }
        } finally {
            httpClient.close(); // 确保关闭 HttpClient
        }
    }
}